libobs_wrapper\data\properties\types/
mod.rs

1//! # Important Notice
2//! All structs in this module use direct obs calls to get the data from the obs_property_t struct. **ALWAYS MAKE SURE THIS IS RUNNING ON THE OBS THREAD**
3
4mod button;
5impl_general_property!(Color);
6mod editable_list;
7impl_general_property!(Font);
8impl_general_property!(FrameRate);
9impl_general_property!(Group);
10impl_general_property!(ColorAlpha);
11mod list;
12mod number;
13mod path;
14mod text;
15
16pub(crate) struct PropertyCreationInfo {
17    name: String,
18    description: Option<String>,
19    pointer: Sendable<*mut libobs::obs_property>,
20    runtime: ObsRuntime,
21}
22
23impl PropertyCreationInfo {
24    // # Safety
25    // The caller must ensure that `pointer` is a valid pointer to an `obs_property
26    pub(crate) unsafe fn new(
27        name: String,
28        description: Option<String>,
29        pointer: Sendable<*mut libobs::obs_property>,
30        runtime: ObsRuntime,
31    ) -> Self {
32        Self {
33            name,
34            description,
35            pointer,
36            runtime,
37        }
38    }
39}
40
41use std::ffi::CStr;
42
43pub use button::*;
44pub use editable_list::*;
45use libobs::obs_property;
46pub use list::*;
47pub use number::*;
48pub use path::*;
49pub use text::*;
50
51use crate::{run_with_obs, runtime::ObsRuntime, unsafe_send::Sendable, utils::ObsError};
52
53use super::{macros::impl_general_property, ObsProperty, ObsPropertyType};
54
55impl ObsPropertyType {
56    /// Safety:
57    /// The caller must ensure that `pointer` is non-null and points to a valid
58    /// `libobs::obs_property` instance for the duration of this call.
59    unsafe fn inner_to_property_struct(
60        &self,
61        runtime: &ObsRuntime,
62        pointer: Sendable<*mut obs_property>,
63    ) -> Result<ObsProperty, ObsError> {
64        let (name, description) = run_with_obs!(runtime, (pointer), move || {
65            let name = unsafe {
66                // Safety: The pointer is valid because the caller ensured it.
67                libobs::obs_property_name(pointer.0)
68            };
69            if name.is_null() {
70                return Err(ObsError::NullPointer(Some(
71                    "Property name pointer is null".to_string(),
72                )));
73            }
74
75            let name = unsafe {
76                // Safety: We made sure that the name pointer is valid because it is not null.
77                CStr::from_ptr(name)
78            };
79            let name = name.to_string_lossy().to_string();
80
81            let description = unsafe { libobs::obs_property_description(pointer.0) };
82            let description = if description.is_null() {
83                None
84            } else {
85                let description = unsafe {
86                    // Safety: We made sure that the description pointer is valid because it is not null.
87                    CStr::from_ptr(description)
88                };
89                Some(description.to_string_lossy().to_string())
90            };
91
92            Ok((name, description))
93        })??;
94
95        let info = PropertyCreationInfo::new(
96            name,
97            description,
98            pointer,
99            runtime.clone(), //
100        );
101
102        let data = match self {
103            ObsPropertyType::Invalid => ObsProperty::Invalid,
104            ObsPropertyType::Bool => ObsProperty::Bool,
105            ObsPropertyType::Int => ObsProperty::Int(ObsNumberProperty::<i32>::try_from(info)?),
106            ObsPropertyType::Float => ObsProperty::Float(ObsNumberProperty::<f64>::try_from(info)?),
107            ObsPropertyType::Text => ObsProperty::Text(ObsTextProperty::try_from(info)?),
108            ObsPropertyType::Path => ObsProperty::Path(ObsPathProperty::try_from(info)?),
109            ObsPropertyType::List => ObsProperty::List(ObsListProperty::try_from(info)?),
110            ObsPropertyType::Color => ObsProperty::Color(ObsColorProperty::try_from(info)?),
111            ObsPropertyType::Button => ObsProperty::Button(ObsButtonProperty::try_from(info)?),
112            ObsPropertyType::Font => ObsProperty::Font(ObsFontProperty::try_from(info)?),
113            ObsPropertyType::EditableList => {
114                ObsProperty::EditableList(ObsEditableListProperty::try_from(info)?)
115            }
116            ObsPropertyType::FrameRate => {
117                ObsProperty::FrameRate(ObsFrameRateProperty::try_from(info)?)
118            }
119            ObsPropertyType::Group => ObsProperty::Group(ObsGroupProperty::try_from(info)?),
120            ObsPropertyType::ColorAlpha => {
121                ObsProperty::ColorAlpha(ObsColorAlphaProperty::try_from(info)?)
122            }
123        };
124
125        Ok(data)
126    }
127
128    /// Note to future self: I've tried to refactor this to use SmartPointerSendable directly, but the pointer of the
129    /// iteration class shouldn't be freed, so its better to just use the raw pointer directly.
130    /// # Safety
131    /// You must make sure that `pointer` is a valid pointer to an `obs_property_t` struct.
132    pub(in crate::data::properties) unsafe fn get_property_struct(
133        &self,
134        runtime: &ObsRuntime,
135        pointer: Sendable<*mut obs_property>,
136    ) -> Result<ObsProperty, ObsError> {
137        self.inner_to_property_struct(runtime, pointer)
138    }
139}